다양한 예제로 직접 시도하여 if문과 for문을 익히시길 바랍니다. if문과 for문은 또한 프로그래밍 문법의 기본이니 잘 알아두시면 유용할 것입니다.
9-3. dplyr 라이브러리를 활용한 데이터 처리
지금까지 강의에서 중간중간 dplyr 패키지의 함수들을 다뤘습니다. 이번 기회에 좀 더 자세하게 살펴보겠습니다. dplyr 패키지는 대체로 함수가 직관적으로 만들어져 있어 금방 익힐 수 있고 빠르고 또 다양한 상황의 데이터 처리 함수를 제공합니다. Cheatsheet도 함께 보면서 공부해보세요.
filter
filter함수는 특정 조건에 해당 하는 행(row)을 추출합니다. 그간 예제에서 자주 사용하여 금방 아실 것입니다. 예를 들어, 자격 테이블(bnc)에서 남자들만 추출해봅시다. 첫 번째는 타겟하는 데이터셋, 다음은 조건이 들어가면 됩니다. 조건은 다양하게 입력할 수 있습니다. 이번엔 STD_YYYY가 2006이고 그 중 남자들만 뽑아봅시다.
bnc_man <-filter(bnc, SEX ==1)bnc_2006_man <-filter(bnc, (STD_YYYY ==2006) & (SEX ==1))
and를 나타내는 &, or를 나타내는 | 또한 잘 알아두세요.
이번엔 STD_YYYY가 2006 또는 2008이고 그중 남자만 뽑는다면 어떻게 해야할까요?
group_by 함수는 말그대로 group 별로 무언가 하고 싶을 때 쓰는 변수 입니다. 예제를 보는 것이 바로 와닿을 것 같습니다. 이번엔 bnc_2006에서 남자, 여자 그룹의 n수를 구해본다고 합시다. 이 때, N수를 구하는 것처럼 요약 정보를 만들고자 할 때는 주로 summarise 함수를 활용합니다.
교육용 표본DB의 3000명에 대해서 검진 테이블에는 2006, 2008, 2010, 2012년 사이에 건강검진을 받은 경우 기록이 되어 있기 때문에 한 사람이 여러번 진단을 받았을 수도 있습니다. 3000명 중에서 건강검진을 받았는 사람들이 몇 명이고, 또 여러 번 받은 사람들이 몇 명인지 알아보려면 어떻게 해야 할까요? 관심 변수의 missing value를 제거한 cohort데이터로 살펴보겠습니다.
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.000 1.000 2.000 2.096 3.000 4.000
cohort에 포함된 사람들의 BMI, SBP, DBP, total chol., smoking 변수의 대푯값을 구하겠습니다. 특히 여러 번 건강검진을 받은 사람들의 BMI, SBP, DBP, total chol.은 평균, smoking 변수는 max 값으로 구하기로 정의합시다.
즉, group_by함수를 활용해 자신이 원하는 그룹의 요약통계량이나 대푯값을 어렵지 않게 코드 한 줄로 구할 수 있습니다.
arrange
arrange는 말그대로 배치하는 것인데 특정 열을 기준으로 테이블을 sorting을 할 때 씁니다. 예를 들어 bnd에서 BTH_YYYY를 기준으로 오름차순 정렬해봅시다.
tmp_bnd <- bnd %>%arrange(BTH_YYYY)
빠른 생년 기준으로 정렬된 것이 보이나요? 만약에 내림차순으로 정렬한다면 어떻게 해야할까요? desc()함수를 함께 써줍니다.
tmp_bnd <- bnd %>%arrange(desc(BTH_YYYY))
distinct
벡터에서 값들을 unique하게 보고 싶다면 unique 함수를 쓰면 됩니다. 마찬가지로 데이터프레임에서 특정 열을 기준으로 unique하게 뽑고 싶다면 distinct함수를 사용합니다. 예를 들어, g1e 테이블에는 한 사람이 건강검진을 여러 번을 받았다는 것이 기록 되어 있습니다. 만약에 g1e에서 사람들을 unique하게 뽑고 싶다면 어떻게 해야할까요?
unique(cohort$Q_SMK_YN)
Warning: Unknown or uninitialised column: `Q_SMK_YN`.
NULL
tmp_g1e <- g1e %>%distinct(RN_INDI)
tmp_g1e를 보시면 RN_INDI말고 모든 변수가 사라졌습니다. 만약 나머지 변수들도 함께 뽑고 싶다면 .keep_all=True 옵션을 줍니다. 이 때, 한 사람이 여러 번 건강검진을 받았다면 g1e 테이블에서 가장 첫번째 row만 가져오게 됩니다.
rename은 열의 이름을 바꾸고자 할 때 유용하게 쓸 수 있는 함수입니다. 예제를 보시면 금방 이해할 수 있습니다. AGE 변수를 age로 바꿔보겠습니다.
bnd <- bnd %>%rename(age = AGE)
저는 보통 열의 이름을 모두 대문자로 하기 때문에 다시 AGE로 바꿀게요.
bnd <- bnd %>%rename(AGE = age)
9-4. 테이블의 결합 (Join)
데이터의 변수가 많아질수록 한 테이블에 담기가 어려워집니다. 보기도 힘들어집니다. 그래서 공통된 특성끼리 묶어 여러 개의 테이블을 만듭니다. 자격, 사망, 명세서 등 테이블이 여러 개가 있는 건보공단 데이터도 그렇습니다. 그럼 테이블을 결합할 땐 어떤 방식으로 할까요? 이 때 알아야 할 개념이 key입니다. 두 테이블을 연결해줄 공통적인 열을 의미합니다.
현재 AGE변수는 bnd에 있고 BMI 변수는 cohort에 있습니다. 이를 하나의 테이블에서 보려면 어떻게 해야 할까요? 사람별로 AGE, BMI 변수를 찾아 합쳐줘야 할텐데 개인식별아이디 RN_INDI를 사용할 수 있을 것입니다. 여기서 RN_INDI가 key가 됩니다.
한 가지 더 알아야 하는 것은 어느 테이블을 기준으로 합칠 것인지 또는 합집합, 교집합으로 합칠 것인지 따져야 합니다. 아래 cheatsheet의 예제를 보면서 비교해보세요.
목적에 따라 left_join을 할지, inner_join을 할지, full_join을 할지 그때 그때 다르기 때문에 잘 이해했다가 적용해야합니다. cohort 데이터에 건강검진 변수가 있는데 여기에 AGE 변수를 합치도록 하겠습니다. 그러면 cohort 데이터를 기준으로 합치는 것이니 left_join이 적절할 것입니다.
cohort2 <-left_join(cohort, select(bnd, RN_INDI, AGE), by ="RN_INDI")nrow(cohort2)
[1] 1162
이번엔 bnc테이블의 SEX 변수도 함께 합치겠습니다.
cohort3 <-left_join(cohort2, select(bnc, RN_INDI, SEX), by ="RN_INDI")
Warning in left_join(cohort2, select(bnc, RN_INDI, SEX), by = "RN_INDI"): Each row in `x` is expected to match at most 1 row in `y`.
ℹ Row 1 of `x` matches multiple rows.
ℹ If multiple matches are expected, set `multiple = "all"` to silence this
warning.
nrow(cohort3)
[1] 4624
경고와 함께 cohort3의 행의 수가 더 많아졌습니다. 왜 그런 것인가요? bnc테이블에 환자가 중복되어 있기 때문에 합쳤을 때 수가 늘어난 것입니다. 현재는 cohort 데이터에 환자가 중복되어 있지 않게끔 구성하고 싶기 때문에 원하는 바대로 합쳐지지 않았습니다. 그렇기 때문에 다음과 같이 해야 합니다.
cohort3 <-left_join(cohort2, select(bnc, RN_INDI, SEX) %>%distinct(RN_INDI, .keep_all =TRUE), by ="RN_INDI")nrow(cohort3)
[1] 1162
방금 예시를 통해 보았듯 데이터를 조인하게 될 경우가 빈번하게 생길텐데 그럴 때 본인이 갖고 있는 테이블들의 키가 중복되어 있는지 unique하게 하나씩만 있는지 잘 파악하면서 데이터처리를 해야 합니다.
9-5. 건보공단 데이터에 적용하기
데이터 처리를 할 때 잘 쓰는 dplyr 패키지의 함수를 배웠습니다. 이외에 또 다양한 상황에 맞는 함수가 존재합니다. 그러니 만들고자 하는 데이터의 형태가 어떻게 되어야 할지 생각해서 그에 맞는 함수를 찾으면 됩니다.
이제는 지금까지 배운 함수를 토대로 중간 시험에서 사용했던 cohort를 만들어보려고 합니다. 잘 해석해보도록 합시다.
Welch Two Sample t-test
data: filter(data, HYP == 1)$TOT_CHOL and filter(data, HYP == 0)$TOT_CHOL
t = 3.7837, df = 495.11, p-value = 0.0001735
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
4.138246 13.078552
sample estimates:
mean of x mean of y
201.5006 192.8922
Wilcoxon rank sum test with continuity correction
data: filter(data, HYP == 1)$TOT_CHOL and filter(data, HYP == 0)$TOT_CHOL
W = 145712, p-value = 0.0001283
alternative hypothesis: true location shift is not equal to 0
# 9.table(data$HYP, data$IHD)
0 1
0 846 25
1 230 61
chisq.test(data$HYP, data$IHD)
Pearson's Chi-squared test with Yates' continuity correction
data: data$HYP and data$IHD
X-squared = 101.55, df = 1, p-value < 2.2e-16